/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
  //
// Copyright (c) 2006 Georgia Tech Research Corporation
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation;
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Author: George F. Riley<riley@ece.gatech.edu>
//

#include "flow-client.h"

NS_LOG_COMPONENT_DEFINE ("FlowClient");

using namespace std;

namespace ns3 {

NS_OBJECT_ENSURE_REGISTERED (FlowClient);
  
FlowClient::FlowClient(Ptr<Node> node)
{
  m_socket = Socket::CreateSocket (node, TcpSocketFactory::GetTypeId());
  m_socket->Bind ();
  m_socket->SetRecvCallback ( MakeCallback(&FlowClient::HandleRead, this) );
}      

FlowClient::~FlowClient ()
{
  NS_LOG_FUNCTION_NOARGS ();
}

void
FlowClient::SetFlowFinishCallback( Callback<void, Ptr<FlowClient> > flowFinished )
{
  NS_LOG_FUNCTION_NOARGS ();
  m_flowFinished = flowFinished;
}

void
FlowClient::Start (const Address &peer, uint32_t size)
{
  NS_LOG_FUNCTION_NOARGS ();
  if(!InetSocketAddress::IsMatchingType (peer))
  {
    // fail silently for now
    return;
  }

  NS_ASSERT ( size );
  m_flowSize = size;
  m_dataToRecv = size;

  m_socket->Connect (peer);                  


  //flow size is a uin32_t
  int dataToSend = 4;
  uint8_t buffer[dataToSend];
  memset(buffer, 0, dataToSend);
  for( uint8_t i = 0; i < dataToSend ; i++ )
  {
    buffer[i] = (( m_flowSize >> i*8) & 0xff );
  }
  
  //send size in first packet (request)
  Ptr<Packet> packet = Create<Packet> (buffer, dataToSend);
  m_socket->Send (packet);
}                                                      

void
FlowClient::HandleRead(Ptr<Socket> socket) 
{
  NS_LOG_FUNCTION (this << socket );

  Address from;
  Ptr<Packet> packet;

  while (packet = socket->RecvFrom (from))
  {
    m_dataToRecv -= packet->GetSize();
    NS_LOG_FUNCTION (this << m_dataToRecv);
  }

  // all requested data was received
  if ( !m_dataToRecv )
  {
    Stop();

    if ( !m_flowFinished.IsNull() ) 
      m_flowFinished (this);
  }
}

void 
FlowClient::Stop ()
{
  // close connection, cancel callback
  NS_LOG_FUNCTION(this << m_socket);
  m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
  m_socket->Close();
}
  
} // Namespace ns3
